package com.lsa.iview.chap1;

import java.util.LinkedList;
import java.util.List;

import org.apache.commons.lang.mutable.MutableInt;
import org.junit.Assert;
import org.junit.Test;

import com.lsa.helpers.IClosure;
import com.lsa.helpers.Pair;
import com.lsa.helpers.Utils;

public class StringQuestionsTest {

	@Test
	public void testIsAllCharsUniqueInplace() {
		testAllCharsUnique(new IClosure<String, Boolean, Exception>() {
			@Override
			public Boolean invoke(String s) throws Exception {
				return StringQuestions.isAllCharsUniqueInplace(s);
			}
		});
	}
	
	@Test
	public void testIsAllCharsUniqueAscii() {
		testAllCharsUnique(new IClosure<String, Boolean, Exception>() {
			@Override
			public Boolean invoke(String s) throws Exception {
				return StringQuestions.isAllCharsUniqueAscii(s);
			}
		});
	}
	
	@Test
	public void testRotation() {
		Assert.assertTrue(StringQuestions.isRotation("waterbottle", "erbottlewat"));
		Assert.assertTrue(StringQuestions.isRotation("erbottlewat", "waterbottle"));
		Assert.assertFalse(StringQuestions.isRotation("erbotelewat", "waterbottle"));
	}

	private void testAllCharsUnique(IClosure<String, Boolean, Exception> method) {
		try {
			Assert.assertFalse(method.invoke("aaaa"));
			Assert.assertTrue(method.invoke("a"));
			Assert.assertTrue(method.invoke(""));
			
			Assert.assertFalse(method.invoke("aabb"));
			Assert.assertFalse(method.invoke("abab"));
			
			Assert.assertTrue(method.invoke("abcdef"));
			
			char cStart = 'a';
			char cEnd = 'z';
			char[] chars = new char[cEnd - cStart + 1];
			int[] counts = new int[cEnd - cStart + 1];
			int[] counts2 = new int[cEnd - cStart + 1];
			for (int i = cStart; i <= cEnd; i++) {
				chars[i - cStart] = (char)i;
				counts[i - cStart] = 1;
				counts2[i - cStart] = 2;
			}
			Assert.assertTrue(method.invoke(generateTestString(chars, counts)));
			Assert.assertFalse(method.invoke(generateTestString(chars, counts2)));
			
			System.out.println(generateTestString(new char[]{'e', 'f', 'g'}, new int[]{1, 1, 1}));
		} catch (Exception e) {
			System.out.println(e);
			Assert.assertFalse(true);
		}
	}
	
	private String generateTestString(char[] chars, int[] counts) {
		List<Pair<Character, MutableInt>> patterns = new LinkedList<Pair<Character,MutableInt>>();

		for (int i = 0; i < chars.length; i++) {
			patterns.add(new Pair<Character, MutableInt>(chars[i], new MutableInt(counts[i])));
		}
		
		return generateTestString(patterns);
	}
	
	private String generateTestString(List<Pair<Character, MutableInt>> patterns) {
		StringBuilder sb = new StringBuilder();
		
		while(patterns.size() > 0) {
			int randomIdx = Utils.random(0, patterns.size() - 1);
			Pair<Character, MutableInt> entry = patterns.get(randomIdx);
			entry.getSecond().decrement();
			if (entry.getSecond().intValue() == 0) {
				patterns.remove(randomIdx);
			}
			else if (entry.getSecond().intValue() < 0) {
				throw new RuntimeException("Incorrect prg!");
			}
			
			sb.append(entry.getFirst());
		}
		
		return sb.toString();
	}
}
